package com.pan.alg.structure;

import java.util.LinkedList;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现一个简单的阻塞队列
 * 可对比一下java提供的几种队列
 */
public class GBlockingQueue<T> {

    /**
     * javai提供的阻塞队列，方便查看，与实际实现阻塞队列没有关系
     * 由数组结构组成的有界阻塞队列。
     */
    ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(16);
    /**
     * 由链表结构组成的有界阻塞队列
     * LinkedBlockingQueue 之所以能够高效的处理并发数据，还因为其对于生产者 端和消费者端分别采用了独立的锁来控制数据同步，这也意味着在高并发的情况下生产者和消费 者可以并行地操作队列中的数据，以此来提高整个队列的并发性能
     */
    LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(16);
    /**
     * 支持优先级排序的无界阻塞队列。
     */
    PriorityBlockingQueue priorityBlockingQueue = new PriorityBlockingQueue(16);
    /**
     * 使用优先级队列实现的无界阻塞队列。
     */
    DelayQueue delayQueue = new DelayQueue();
    /**
     * 不存储数据，只用于传递数据
     */
    SynchronousQueue synchronousQueue = new SynchronousQueue();
    /**
     * 由链表结构组成的无界阻塞队列。
     */
    LinkedTransferQueue linkedTransferQueue = new LinkedTransferQueue();
    /**
     * 由链表结构组成的双向阻塞队列
     */
    LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque();

    ReentrantLock reentrantLock = new ReentrantLock();
    Condition empty = reentrantLock.newCondition();
    Condition full = reentrantLock.newCondition();
    LinkedList<T> linkedList;
    private int capacity;
    private int count;

    public GBlockingQueue(){
        this.capacity =16;
        linkedList = new LinkedList<T>();
    }
    public GBlockingQueue(int capacity){
        this.capacity = capacity;
        linkedList = new LinkedList<T>();
    }

    public void put(T t){
        reentrantLock.lock();
        try{
            while(count==capacity){
                full.wait();
            }
            linkedList.add(t);
            count++;
            empty.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }


    public T take() throws InterruptedException {
        reentrantLock.lock();
        try {
            while(count==0){
                empty.wait();
            }
            T pop = linkedList.pop();
            full.signal();
            count--;
            return pop;
        } finally {
            reentrantLock.unlock();
        }
    }

}
